//
//  FileCache.swift
//  ZLKit_SwiftDemo_Example
//
//  Created by itzhaolei on 2022/1/17.
//  Copyright © 2022 CocoaPods. All rights reserved.
//

import Alamofire

public protocol ZLFileCacheHeader {
    
    /// 将缓存中的图片写入内存
    /// - Parameters:
    ///   - image: 图片对象
    ///   - identifier: 唯一标识
    ///   - completion: 异步结果（Bool：是否成功，String：唯一标识，String：存储路径）
    static func write(image: UIImage, identifier: String, completion: Params_three_void<Bool, String, String?>)
    
    
    /// 将缓存中的Data写入内存
    /// - Parameters:
    ///   - data: 二进制对象
    ///   - isImage: 是否是图片中转过来的
    ///   - identifier: 唯一标识
    ///   - completion: 异步结果（Bool：是否成功，String：唯一标识，String：存储路径）
    static func write(data: Data, isImage: Bool, identifier: String, completion: Params_three_void<Bool, String, String?>)
    
    
    /// 将远程URL的资源写入内存
    ///
    /// 根据类型会规划文件进行分组
    static func write(url: String, type: ZLFileCache.FileCachePath.DirectoryType, identifier: String?, completion: Params_three_void<Network.RequestedState, String, String?>)
    
    
    /// 删除指定文件
    static func remove(path: String)
    
    
    /// 重置缓存器，存储的文件会被删除
    static func resetFileCache()
    
}

open class ZLFileCache: NSObject, ZLFileCacheHeader {
    
    static let fileLoader: Network.Download = .init()
    
    /// 将缓存中的图片写入内存
    /// - Parameters:
    ///   - image: 图片对象
    ///   - identifier: 唯一标识
    ///   - completion: 异步结果（Bool：是否成功，String：唯一标识，String：存储路径）
    static public func write(image: UIImage, identifier: String = UUID().uuidString, completion: Params_three_void<Bool, String, String?>) {
        DispatchQueue.global().async {
            write(data: image.jpegData(compressionQuality: 1.0) ?? .init(), isImage: true, identifier: identifier, completion: completion)
        }
    }
    
    /// 将缓存中的Data写入内存
    /// - Parameters:
    ///   - data: 二进制对象
    ///   - isImage: 是否是图片中转过来的
    ///   - identifier: 唯一标识
    ///   - completion: 异步结果（Bool：是否成功，String：唯一标识，String：存储路径）
    static public func write(data: Data, isImage: Bool = false, identifier: String = UUID().uuidString, completion: Params_three_void<Bool, String, String?>) {
        DispatchQueue.global().async {
            let path = "\(FileCachePath.path(type: isImage ? .image : .data))"
            if !FileManager.default.fileExists(atPath: path) {
                try? FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
            }
            let name = FileCachePath.name()
            let allPath = "\(path)/\(name)"
            do {
                try data.write(to: .init(fileURLWithPath: allPath), options: .atomic)
                DispatchQueue.main.sync {
                    completion?(true, identifier, allPath)
                }
            }catch {
                print("error.localizedDescription = \(error.localizedDescription)")
                DispatchQueue.main.sync {
                    completion?(false, identifier, nil)
                }
            }
            
        }
    }
    
    /// 将远程URL的资源写入内存
    ///
    /// 根据类型会规划文件进行分组
    ///
    static public func write(url: String, type: FileCachePath.DirectoryType = .multimedia, identifier: String? = nil, completion: Params_three_void<Network.RequestedState, String, String?>) {
        let path = "\(FileCachePath.path(type: type))/\(FileCachePath.name(url: url))"
        fileLoader.download(fromUrlString: url, toPath: path, identifier: url, completion: completion)
    }
    
    /// 删除指定文件
    static public func remove(path: String) {
        try? FileManager.default.removeItem(atPath: path)
    }
    
    /// 重置缓存器，存储的文件会被删除
    static public func resetFileCache() {
        try? FileManager.default.removeItem(atPath: FileCachePath.rootPath())
    }
    
}

public extension ZLFileCache {
    
    class FileCachePath: NSObject {
        
        public enum DirectoryType: String {
            case multimedia = "Multimedias"
            case image = "Images"
            case video = "Videos"
            case data = "Datas"
        }
        
        /// 沙盒目录
        static let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first ?? .init(fileURLWithPath: "")
        
        /// 文件根目录
        static public func rootPath() -> String {
            return ((NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true) as [String]).first ?? "") + "/ZLKit_Swift"
        }
        
        /// 根据类型指定文件目录
        static public func path(type: DirectoryType) -> String {
            return rootPath() + "/\(type.rawValue)"
        }
        
        static public func name(url: String? = nil) -> String {
            var name = ""
            if let url = url {
                name = url.hashHex(by: .MD5).lowercased()
            }else {
                // 日期 + 1000内的随机数
                name = "\(dateFormatter().string(from: .init()))\(arc4random()%1000)".hashHex(by: .MD5).lowercased()
            }
            return name
        }
        
    }
    
}

// 下载/上传
enum ZLFileCache_IO: URLRequestConvertible {
    
    case download(url: String)
    case upload(url: String)
    
    func asURLRequest() -> URLRequest {
        let url: URL = {
            let thisUrl: URL
            switch self {
            case .download(let url):
                thisUrl = URL.init(string: url) ?? .init(fileURLWithPath: "")
            case .upload(let url):
                thisUrl = URL.init(string: url) ?? .init(fileURLWithPath: "")
            }
            return thisUrl
        }()
        
        var method: HTTPMethod {
            switch self {
            case .download:
                return .get
            case .upload:
                return .put
            }
        }
        
        let params: ([String: Any]?) = {
            switch self {
            case .download:
                return nil
            case .upload:
                return nil
            }
        }()
        
        return request(url: url, method: method, allHTTPHeaderFields: [:], params: params)
    }
}


// 下载文件
public extension Network.Download {
    
    /// 下载文件
    func download(fromUrlString: String, toPath: String, identifier: String, completion: Params_three_void<Network.RequestedState, String, String?>) {
        request(from: ZLFileCache_IO.download(url: fromUrlString), toPath: toPath, identifier: identifier, completion: completion)
    }
    
}
